// wrap all the options and method in one instead of all over the places
import { join, resolve } from 'path'
import fsx from 'fs-extra'
import _ from 'lodash'
import { checkConfig, isString } from 'jsonql-params-validator'
import { rsaPemKeys } from 'jsonql-jwt'

import { appProps, constProps, jwtProcessKey } from './options'
import { isContract, chainFns, getDebug, inArray } from '../utils'
import { getContract } from '../contracts'
const debug = getDebug('config-check')

/**
 * break out from the applyAuthOptions because it's not suppose to be there
 * @NOTE v1.3.8 change it to a fully functional interface
 * @param {object} config configuration
 * @return {object} with additional properties
 */
const applyGetContract = function(config) {
  return _(config)
    .chain()
    .thru(config => {
      const { contract } = config;
      if (isContract(contract)) {
        config.contract = contract;
        return [true, config]
      }
      return [false, config]
    })
    .thru(result => {
      let [processed, config] = result
      if (!processed) {
        debug(`call initContract`)
        // get resolve later inside the middleware
        config.initContract = getContract(config)
      }
      return config;
    })
    .thru(config => {
      if (config.withPublicContract) {
        debug(`call generate public contract`)
        getContract(config, true)
      }
      return config;
    })
    .value()
}

/**
 * we need an extra step to cache some of the auth related configuration data
 * ASYNC AWAIT IS A FUCKING JOKE
 * @param {object} config configuration
 * @return {object} config with extra property
 */
const applyAuthOptions = function(config) {
  if (config.enableAuth && config.useJwt && !isString(config.useJwt)) {
    const { keysDir, publicKeyFileName, privateKeyFileName } = config;
    const publicKeyPath = join(keysDir, publicKeyFileName)
    const privateKeyPath = join(keysDir, privateKeyFileName)
    if (fsx.existsSync(publicKeyPath) && fsx.existsSync(privateKeyPath)) {
      config.publicKey = fsx.readFileSync(publicKeyPath)
      config.privateKey = fsx.readFileSync(privateKeyPath)
    } else {
      // we only call here then resolve inside the init-middleware
      config[jwtProcessKey] = rsaPemKeys(config.rsaModulusLength, config.keysDir)
    }
  }
  return config;
}

/**
 * @param {object} config configuration supply by developer
 * @return {object} configuration been checked
 * @api public
 */
export function configCheck(config) {
  const fn = chainFns(checkConfig, applyGetContract, applyAuthOptions)
  return fn(config, appProps, constProps)
}
